/**
* 1.内部可变性（Interior mutability）是 Rust 中的一个设计模式，它允许你即使在有不可变引用时也可以改变数据，这通常是借用规则所不允许的
* 2.为了改变数据，该模式在数据结构中使用 unsafe 代码来模糊 Rust 通常的可变性和借用规则
* 3.所涉及的 unsafe 代码将被封装进安全的 API 中，而外部类型仍然是不可变的(仅仅是看起来不可变而已)
*
* 4.在运行时检查借用规则的好处则是允许出现特定内存安全的场景，而它们在编译时检查中是不允许的
*   代码的一些属性不可能通过分析代码发现：其中最著名的就是 停机问题（Halting Problem）
* 5.RefCell<T> 正是用于当你确信代码遵守借用规则，而编译器不能理解和确定的时候
* 6.RefCell<T> 只能用于单线程场景
*
* 7.在不可变值内部改变值就是 内部可变性 模式
*
*
* 实现机制
* 1.RefCell提供两个借用方法
*   borrow() 方法返回一个对值的可变引用 Ref<T>，但是它要求当前的借用状态允许这么做
*   borrow_mut() 方法返回一个对值的可变引用RefMut<T>，但是它要求当前的借用状态允许这么做
* 2.RefCell<T> 记录当前有多少个活动的 Ref<T> 和 RefMut<T> 智能指针。
*   每次调用 borrow，RefCell<T> 将活动的不可变借用计数加一。当 Ref<T> 值离开作用域时，不可变借用计数减一。
*   就像编译时借用规则一样，RefCell<T> 在任何时候只允许有多个不可变借用或一个可变借用

* RefCell<T> 常见用法
* 1.RefCell<T> 的一个常见用法是与 Rc<T> 结合. Rc<T> 允许对相同数据有多个所有者，不过只能提供数据的不可变访问。
*    如果有一个储存了 RefCell<T> 的 Rc<T> 的话，就可以得到有多个所有者 并且 可以修改的值了！

*/
use std::cell::RefCell;

pub trait Messenger {
    fn send(&self, msg: &str);
}

pub struct LimitTracker<'a, T: Messenger> {
    messenger: &'a T,
    value: usize,
    max: usize,
}

impl<'a, T> LimitTracker<'a, T>
where
    T: Messenger,
{
    pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> {
        LimitTracker {
            messenger,
            value: 0,
            max,
        }
    }

    pub fn set_value(&mut self, value: usize) {
        self.value = value;

        let percentage_of_max = self.value as f64 / self.max as f64;

        if percentage_of_max >= 1.0 {
            self.messenger.send("Error: You are over your quota!");
        } else if percentage_of_max >= 0.9 {
            self.messenger
                .send("Urgent warning: You've used up over 90% of your quota!");
        } else if percentage_of_max >= 0.75 {
            self.messenger
                .send("Warning: You've used up over 75% of your quota!");
        }
    }
}

fn main(){
    let mock_messenger = MockMessenger::new();
    let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
    limit_tracker.set_value(80);
    assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
}

/**
 * RefCell<T> 示例
 */
struct MockMessenger {
    //sent_messages: Vec<String>,
    sent_messages: RefCell<Vec<String>>
}

impl MockMessenger {
    fn new() -> MockMessenger {
        MockMessenger {
            //sent_messages: vec![],
            sent_messages: RefCell::new(vec![])
        }
    }
}

impl Messenger for MockMessenger {
    fn send(&self, message: &str) {
        //self.sent_messages.push(String::from(message));
        println!("{}", message);
        self.sent_messages.borrow_mut().push(String::from(message));
    }
}